package checkers3d.logic;

import java.awt.*;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.*;
import checkers3d.storage.*;
import checkers3d.presentation.*;
import java.util.logging.Level;
import javax.swing.JOptionPane;

/**
 * Allows for two players to login and start playing a scenario.
 *
 * @author Ruben Acuna
 */
public class MenuLoadGameLoginMP extends GUIContainer
{
    /**
     * Y axis value along which buttons will be centered.
     */
    private final int CONTROL_BUTTON_AXIS = 500;

    /**
     * Name of the selected scenario.
     */
    private String scenarioName;

    /**
     * Reference the play button that the player clicks to start.
     */
    GUIButton buttonPlay;

    /**
     * GUI component for getting homes name.
     */
    GUITextbox loginHomeName;

    /**
     * GUI component for getting the homes password.
     */
    GUITextbox loginHomePassword;

    /**
     * GUI component that displays the homes validation state as a color.
     */
    GUILabel loginHomeValidation;

    /**
     * GUI component for getting visitors name.
     */
    GUITextbox loginVisitorName;

    /**
     * GUI component for getting the visitors password.
     */
    GUITextbox loginVisitorPassword;

    /**
     * GUI component that displays the visitors validation state as a color.
     */
    GUILabel loginVisitorValidation;

    private String usernameHome;
    private String usernameVisitor;

    public MenuLoadGameLoginMP(Point size, String usernameHome, String usernameVisitor)
    {
        super(size);
        this.usernameHome = usernameHome;
        this.usernameVisitor = usernameVisitor;
        
        LinkedList<IDrawable> buttons = new LinkedList<IDrawable>();

        //add background image.
        add(new GUIPictureBox("Background.png", new Point()));

        //create the start button with behavior.
        //buttons.add(new GUIButton("button-start.png", null, new ObserverPlay(scenarioName)));
        buttonPlay = new GUIButton("button-start.png", null, new ObserverPlay());
        buttons.add(buttonPlay);

        //create the return button with behavior.
        buttons.add(new GUIButton("button-return.png", null, new ObserverReturn()));

        //add labels
        add(new GUILabel("Home Login", Color.WHITE, new Point(191, 250)));
        add(new GUILabel("Name:", Color.WHITE, new Point(124, 302)));
        add(new GUILabel("Password:", Color.WHITE, new Point(102, 322)));
        loginHomeValidation = new GUILabel("Ready", Color.RED, new Point(207, 270));
        add(loginHomeValidation);
        add(new GUILabel("Visitor Login", Color.WHITE, new Point(191 + 352, 250)));
        add(new GUILabel("Name:", Color.WHITE, new Point(124 + 352, 302)));
        add(new GUILabel("Password:", Color.WHITE, new Point(102 + 352, 322)));
        loginVisitorValidation = new GUILabel("Ready", Color.RED, new Point(207 + 352, 270));
        add(loginVisitorValidation);
        
        //add the textbox for both players name and password.
        loginHomeName = new GUITextbox(new Point(166, 300), 25, this);
        loginHomeName.setFocus(true);
        loginHomeName.setText(usernameHome);
        this.onKeyPress(' ');
        loginHomeName.setFocus(false);
        loginHomePassword = new GUITextbox(new Point(166, 320), 25, this);
        loginHomePassword.setSecure(true);
        loginVisitorName = new GUITextbox(new Point(166 + 352, 300), 25, this);
        loginVisitorName.setFocus(true);
        loginVisitorName.setText(usernameVisitor);
        this.onKeyPress(' ');
        loginVisitorName.setFocus(false);
        loginVisitorPassword = new GUITextbox(new Point(166 + 352, 320), 25, this);
        loginVisitorPassword.setSecure(true);
        loginHomePassword.setFocus(true);

        //add the buttons to the GUIContainer.
        for(IDrawable component : buttons)
            add(component);

        //compute the positions of the buttons
        UtilGUI.computeLayoutSpanning(getSize(), CONTROL_BUTTON_AXIS, buttons);
    }

    public void cycleTextFieldFocus(){
        if (loginHomePassword.hasFocus()){
            loginHomePassword.setFocus(false);
            loginVisitorPassword.setFocus(true);
        }
        else if (loginVisitorPassword.hasFocus()){
            loginVisitorPassword.setFocus(false);
            loginHomePassword.setFocus(true);
        }
        else {
            loginHomeName.setFocus(false);
            loginVisitorName.setFocus(false);
            loginVisitorPassword.setFocus(false);
            loginHomePassword.setFocus(true);
        }
    }

    /**
     * Updates the validation state embedded in the color of the ready label.
     */
    public void validatePlayers()
    {
        try
        {
            String homeName = loginHomeName.getText();
            String homePassword = loginHomePassword.getText();
            String visitorName = loginVisitorName.getText();
            String visitorPassword = loginVisitorPassword.getText();
            System.out.println(homeName + " " + homePassword);
            System.out.println(visitorName + " " + visitorPassword);
            System.out.println(DataManagerAccounts.getPlayerPassword(homeName)
                    + " " + DataManagerAccounts.getPlayerPassword(visitorName));

            if(DataManagerAccounts.doesPlayerExist(homeName))
                if(DataManagerAccounts.getPlayerPassword(homeName).equals(homePassword))
                    if(!homeName.equals(visitorName))
                        loginHomeValidation.setColor(Color.GREEN);
            else
                loginHomeValidation.setColor(Color.RED);

            if(DataManagerAccounts.doesPlayerExist(visitorName))
                if(DataManagerAccounts.getPlayerPassword(visitorName).equals(visitorPassword))
                    if(!homeName.equals(visitorName))
                        loginVisitorValidation.setColor(Color.GREEN);
            else
                loginVisitorValidation.setColor(Color.RED);
        }
        catch(Exception error)
        {
            loginHomeValidation.setColor(Color.RED);
            loginVisitorValidation.setColor(Color.RED);
        }
    }

    /**
     * Handles a key press, when the GUIContainer is in focus, by sending it to
     * all of its components. If both players are validated, the start button is
     * enabled.
     *
     * @param  key       The character of the key that was pressed.
     */
    @Override
    public void onKeyPress(char key)
    {
        validatePlayers();

        try {
            System.out.println("\n" + DataManagerAccounts.getPlayerPassword(this.usernameHome));
        } catch (FileNotFoundException ex) {
            java.util.logging.Logger.getLogger(MenuLoadGameLoginMP.class.getName()).log(Level.SEVERE, null, ex);
        }

        try {
            System.out.println(DataManagerAccounts.getPlayerPassword(this.usernameVisitor) + "\n");
        } catch (FileNotFoundException ex) {
            java.util.logging.Logger.getLogger(MenuLoadGameLoginMP.class.getName()).log(Level.SEVERE, null, ex);
        }

        if (key == '\t'){
            cycleTextFieldFocus();
        }
        else{
            super.onKeyPress(key);
            if(loginHomeValidation.getColor() == Color.GREEN
               && loginVisitorValidation.getColor() == Color.GREEN)
            {
                Player home = DataManagerAccounts.loadPlayer(loginHomeName.getText());
                Player visitor = DataManagerAccounts.loadPlayer(loginVisitorName.getText());

                buttonPlay.setObserver(new ObserverPlay());
            }
            else
            {
                buttonPlay.setObserver(new ObserverNull());
            }
        }
    }

    /**
     * Returns a string representation of this object containing it's class name.
     *
     * @return String representation.
     */
    @Override
    public String toString()
    {
        return getClass().getName();
    }
    
    /**
     * A observer for a button that creates and displays a new game object based
     * on the selected scenario.
     */
    private class ObserverPlay implements IInputObserver
    {
        /**
         * The home player.
         */
        private Player home;

        /**
         * The visitor player.
         */
        private Player visitor;

        /**
         * Class constructor that keeps a reference to the parent object.
         *
         * @param parent Reference to the parent MenuScenarioSelect object.
         */
        public ObserverPlay()
        {
            // Do nothing.
        }

        /**
         * Creates and displays a new game object based on the selected scenario.
         *
         * @param position Location of click within button.
         */
        public void onClick(Point position)
        {
            // Set user accounts according to usernames and passwords
            home = new Player(loginHomeName.getText(), loginHomePassword.getText());
            visitor = new Player(loginVisitorName.getText(), loginVisitorName.getText());
            // Replay surfaces
            PlayingSurface3D playingSurface3D;
            LinkedList<PlayingSurface3D> savedReplays = null;

            // Filenames are automatically generated by saving a game depending
            // on which user was home or visitor. In order to open the file, we
            // need to "guess" which one it was.
            String gameFilename1 = (DataManagerGame.LOCATION_SAVEGAMES
                    + home.getName() + "&" + visitor.getName() + ".txt");
            String gameFilename2 = (DataManagerGame.LOCATION_SAVEGAMES
                    + visitor.getName() + "&" + home.getName() + ".txt");
            String replayFilename1 = (DataManagerInstantReplay.LOCATION_SAVEREPLAYS
                + visitor.getDataAsString() + "-" + home.getDataAsString() + "-" + "REPLAY.txt");
            String replayFilename2 = (DataManagerInstantReplay.LOCATION_SAVEREPLAYS
                + home.getDataAsString() + "-" + visitor.getDataAsString() + "-" + "REPLAY.txt");

            // Try to load the instant replay file for the game.
            try {
                // Try the first filename.
                System.out.print("\nTrying to read first replay: " + replayFilename1);
                savedReplays = DataManagerInstantReplay.loadInstantReplayData(replayFilename1, home, visitor);
                System.out.print("\nSUCCESS!");
            } catch (IOException e1) {
                System.out.print("\nFAILED!");
                try {
                    // Try the second filename.
                    System.out.print("\nTrying to read second replay: " + replayFilename2);
                    savedReplays = DataManagerInstantReplay.loadInstantReplayData(replayFilename2, home, visitor);
                    System.out.print("\nSUCCESS!");
                } catch (IOException e2) {
                    // If in the case that a game was about to be started but the
                    // program crashes, the game file is created, but not the
                    // instant replay file. When the user restarts the game and
                    // tries to load the game again, the instant replay file is
                    // not found and the exception is thrown. We need to create
                    // a file in this case, but we don't know the order of names
                    // in which the file was written.
                    // FIXME: we need to make user defined filenames because this
                    // is too risky and involves guessing..
                    /*try {
                        DataManagerUtil.createFile(gameFilename1);
                    } catch (IOException ex) {
                        System.out.println("Instant replay file 1 was not created.");
                        try {
                        DataManagerUtil.createFile(gameFilename2);
                        } catch (IOException exp) {
                            System.out.println("Instant replay file 2 was not created.");
                        }
                    }*/
                    JOptionPane.showMessageDialog(null, "Instant replay files could not be found or created.\n" +
                            "An administrator must delete the accounts and new\n" +
                            "accounts must be created.");
                    System.out.print("\nFAILED!");
                }
            }

            // Get possible filenames.
            System.out.println("\n\n" + replayFilename1 + " " + replayFilename2);

            // Try to load the game.
            // The error message should not be reached...
            try {
                System.out.print("\nTrying to read first game: " + gameFilename1);
                playingSurface3D = DataManagerGame.loadGameData(gameFilename1, home, visitor);
                GameMaster.getInstance().addGUIContainer(new Game(home, visitor,
                        DataManagerGame.getCurrentPlayer(), playingSurface3D,
                        savedReplays, getSize()));
                System.out.print("\nSUCCESS!");
            } catch (IOException ex) {
                System.out.print("\nFAILED!");
                try {
                    System.out.print("\nTrying to read second game: " + gameFilename2);
                    playingSurface3D = DataManagerGame.loadGameData(gameFilename2, home, visitor);
                    GameMaster.getInstance().addGUIContainer(new Game(home, visitor,
                        DataManagerGame.getCurrentPlayer(), playingSurface3D,
                        savedReplays, getSize()));
                    System.out.print("\nSUCCESS!");
                } catch (IOException exp) {
                    System.out.print("\nFAILED!");
                }
            }
        }

         /**
         * Key press observer that does nothing.
         *
         * @param key Key that was pressed.
         */
        public void onKeyPress(char key)
        {
            //do nothing.
        }
    }

    /**
     * A observer for a button that returns user to the scenario select screen.
     */
    private class ObserverReturn implements IInputObserver
    {
        /**
         * Returns the user to the scenario select screen.
         *
         * @param position Location of click within button.
         */
        public void onClick(Point position)
        {
            GameMaster.getInstance().removeTopGUIContainer();
        }

         /**
         * Key press observer that does nothing.
         *
         * @param key Key that was pressed.
         */
        public void onKeyPress(char key)
        {
            // Do nothing.
        }
    }

    /**
     * A observer for a button that does nothing.
     */
    private class ObserverNull implements IInputObserver
    {
        /**
         * Does nothing when a click happens.
         *
         * @param position Location of click within button.
         */
        public void onClick(Point position)
        {
            //do nothing.
        }

         /**
         * Key press observer that does nothing.
         *
         * @param key Key that was pressed.
         */
        public void onKeyPress(char key)
        {
            //do nothing.
        }
    }
}